﻿using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Printing;
using System.ComponentModel;
 
using System.Runtime.InteropServices;
using System.IO;
using System.Text.RegularExpressions;

namespace ILookintoControl
{
    public class RichText50W : RichTextBox
    {
        //TextWriter tw;
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            int[] a = { /*0x204e, 0x281, 0x7, 0x2111 ,*/ 0x30 };
            for (int i = 0; i < a.Length; i++)
            {
                if (m.Msg == a[i]) return;
                //this.Rtf = damnit;
                //return;
            }
            //tw.WriteLine(String.Format("{0:x}",  m.Msg));
            //tw.Flush();
            base.WndProc(ref m);

        }

        public CsharpWindowsActiveX.ActiveXUserControl axControl;

        //START : make this control trasparent
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr LoadLibrary(string lpFileName);


        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams prams = base.CreateParams;
                if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
                {
                    //prams.ExStyle |= 0x020; // transparent
                    prams.ClassName = "RICHEDIT50W";
                }
                return prams;
            }
        }
        // END




        public RichText50W()
        {

            // tw = File.CreateText("c:\\temp\\guid3.txt");

            //SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            //SetStyle(ControlStyles.UserPaint, true);
            //SetStyle(ControlStyles.Opaque, true);

            //this.BackColor = Color.Gray;
            ContextMenu cm = new ContextMenu();
            MenuItem mi = new MenuItem("Cut");
            mi.Click += new EventHandler(mi_Cut);
            cm.MenuItems.Add(mi);

            mi = new MenuItem("Copy");
            mi.Click += new EventHandler(mi_Copy);
            cm.MenuItems.Add(mi);

            mi = new MenuItem("Paste");
            mi.Click += new EventHandler(mi_Paste);
            cm.MenuItems.Add(mi);

            mi = new MenuItem("About");
            mi.Click += new EventHandler(mi_About);
            cm.MenuItems.Add(mi);
            this.ContextMenu = cm;
        }

        //Convert the unit used by the .NET framework (1/100 inch) 
        //and the unit used by Win32 API calls (twips 1/1440 inch)
        private const double anInch = 14.4;

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct CHARRANGE
        {
            public int cpMin;         //First character of range (0 for start of doc)
            public int cpMax;           //Last character of range (-1 for end of doc)
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct FORMATRANGE
        {
            public IntPtr hdc;             //Actual DC to draw on
            public IntPtr hdcTarget;       //Target DC for determining text formatting
            public RECT rc;                //Region of the DC to draw to (in twips)
            public RECT rcPage;            //Region of the whole DC (page size) (in twips)
            public CHARRANGE chrg;         //Range of text to draw (see earlier declaration)
        }

        private const int WM_USER = 0x0400;
        private const int EM_FORMATRANGE = WM_USER + 57;

        [DllImport("USER32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

        // Render the contents of the RichTextBox for printing
        //	Return the last character printed + 1 (printing start from this point for next page)
        public int Print(int charFrom, int charTo, PrintPageEventArgs e)
        {
            //Calculate the area to render and print
            RECT rectToPrint;
            rectToPrint.Top = (int)(e.MarginBounds.Top * anInch);
            rectToPrint.Bottom = (int)(e.MarginBounds.Bottom * anInch);
            rectToPrint.Left = (int)(e.MarginBounds.Left * anInch);
            rectToPrint.Right = (int)(e.MarginBounds.Right * anInch);

            //Calculate the size of the page
            RECT rectPage;
            rectPage.Top = (int)(e.PageBounds.Top * anInch);
            rectPage.Bottom = (int)(e.PageBounds.Bottom * anInch);
            rectPage.Left = (int)(e.PageBounds.Left * anInch);
            rectPage.Right = (int)(e.PageBounds.Right * anInch);

            IntPtr hdc = e.Graphics.GetHdc();

            FORMATRANGE fmtRange;
            fmtRange.chrg.cpMax = charTo;				//Indicate character from to character to 
            fmtRange.chrg.cpMin = charFrom;
            fmtRange.hdc = hdc;                    //Use the same DC for measuring and rendering
            fmtRange.hdcTarget = hdc;              //Point at printer hDC
            fmtRange.rc = rectToPrint;             //Indicate the area on page to print
            fmtRange.rcPage = rectPage;            //Indicate size of page

            IntPtr res = IntPtr.Zero;

            IntPtr wparam = IntPtr.Zero;
            wparam = new IntPtr(1);

            //Get the pointer to the FORMATRANGE structure in memory
            IntPtr lparam = IntPtr.Zero;
            lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
            Marshal.StructureToPtr(fmtRange, lparam, false);

            //Send the rendered data for printing 
            res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);

            //Free the block of memory allocated
            Marshal.FreeCoTaskMem(lparam);

            //Release the device context handle obtained by a previous call
            e.Graphics.ReleaseHdc(hdc);

            //Return last + 1 character printer
            return res.ToInt32();
        }

        public int Draw(int charFrom, int charTo, Graphics g, int x, int y, int x1, int y1, double conversion, double conversionY)
        {

            //Calculate the area to render and print
            RECT rectToPrint;
            rectToPrint.Top = (int)(y * conversionY);
            rectToPrint.Bottom = (int)(y1 * conversionY);
            rectToPrint.Left = (int)(x * conversion);
            rectToPrint.Right = (int)(decimal)(x1 * conversion);

            //Calculate the size of the page
            RECT rectPage;
            rectPage.Top = (int)(y * conversionY);
            rectPage.Bottom = (int)(y1 * conversionY);
            rectPage.Left = (int)(x * conversion);
            rectPage.Right = (int)(x1 * conversion);

            IntPtr hdc = g.GetHdc();

            FORMATRANGE fmtRange;
            fmtRange.chrg.cpMax = charTo;				//Indicate character from to character to 
            fmtRange.chrg.cpMin = charFrom;
            fmtRange.hdc = hdc;                    //Use the same DC for measuring and rendering
            fmtRange.hdcTarget = hdc;              //Point at printer hDC
            fmtRange.rc = rectToPrint;             //Indicate the area on page to print
            fmtRange.rcPage = rectPage;            //Indicate size of page


            IntPtr res = IntPtr.Zero;

            IntPtr wparam = IntPtr.Zero;
            wparam = new IntPtr(1);

            //Get the pointer to the FORMATRANGE structure in memory
            IntPtr lparam = IntPtr.Zero;
            lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
            Marshal.StructureToPtr(fmtRange, lparam, false);

            //Send the rendered data for printing 
            res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);

            //Free the block of memory allocated
            Marshal.FreeCoTaskMem(lparam);

            //Release the device context handle obtained by a previous call
            g.ReleaseHdc(hdc);

            //Return last + 1 character printer
            return res.ToInt32();
        }

//Code to add right click

        void mi_Cut(object sender, EventArgs e)
        {
            this.Cut();
        }
        void mi_Copy(object sender, EventArgs e)        
        {
            //Graphics objGraphics;
            Clipboard.SetData(DataFormats.Rtf, this.SelectedRtf);
            Clipboard.Clear();
        }

        void mi_Paste(object sender, EventArgs e)
        {
            if (Clipboard.ContainsText(TextDataFormat.Rtf))
            {
                this.SelectedRtf = Clipboard.GetData(DataFormats.Rtf).ToString();
            }
        }

        void mi_About(object sender, EventArgs e)
        {
            //new AboutBox();

            MessageBox.Show(axControl.Query);
        }


        private void TextChangedEvent(object sender, EventArgs e)
        {
            // Calculate the starting position of the current line.
            int start = 0, end = 0;
            for (start = this.SelectionStart - 1; start > 0; start--)
            {
                if (this.Text[start] == '\n') { start++; break; }
            }

            // Calculate the end position of the current line.
            for (end = this.SelectionStart; end < this.Text.Length; end++)
            {
                if (this.Text[end] == '\n') break;
            }

            // Extract the current line that is being edited.
            String line = this.Text.Substring(start, end - start);

            // Backup the users current selection point.
            int selectionStart = this.SelectionStart;
            int selectionLength = this.SelectionLength;

            // Split the line into tokens.
            Regex r = new Regex("([ \\t{}();])");
            string[] tokens = r.Split(line);
            int index = start;
            foreach (string token in tokens)
            {

                // Set the token's default color and font.
                this.SelectionStart = index;
                this.SelectionLength = token.Length;
                this.SelectionColor = Color.Black;
                this.SelectionFont = new Font("Courier New", 10, FontStyle.Regular);

                // Check for a comment.
                if (token == "//" || token.StartsWith("//"))
                {
                    // Find the start of the comment and then extract the whole comment.
                    int length = line.Length - (index - start);
                    string commentText = this.Text.Substring(index, length);
                    this.SelectionStart = index;
                    this.SelectionLength = length;
                    this.SelectionColor = Color.LightGreen;
                    this.SelectionFont = new Font("Courier New", 10, FontStyle.Regular);
                    break;
                }

                // Check whether the token is a keyword. 
                String[] keywords = { "public", "void", "using", "static", "class" };
                for (int i = 0; i < keywords.Length; i++)
                {
                    if (keywords[i] == token)
                    {
                        // Apply alternative color and font to highlight keyword.        
                        this.SelectionColor = Color.Blue;
                        this.SelectionFont = new Font("Courier New", 10, FontStyle.Bold);
                        break;
                    }
                }
                index += token.Length;
            }
            // Restore the users current selection point.    
            this.SelectionStart = selectionStart;
            this.SelectionLength = selectionLength;
        } 
        #region "Avoid flickering"


        private const int WM_SETREDRAW = 0xB;

        [System.Runtime.InteropServices.DllImport("User32")]

        private static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

        private void FreezeDraw()
        { //Disable drawing

            SendMessage(this.Handle, WM_SETREDRAW, 0, 0);

        }

        private void UnfreezeDraw()
        { //Enable drawing and do a redraw. 

            SendMessage(this.Handle, WM_SETREDRAW, 1, 0);

            this.Invalidate(true);

        }

        #endregion
    }
}

